package com.base.cn.platform.os.common.utils.file.image;

import com.base.cn.platform.os.common.utils.BaseUtil;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.file.FileUtil;
import com.mortennobel.imagescaling.ResampleOp;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.List;

/**
 * 图片处理工具类
 *
 * <p>生成三端图片，PC，H5、APP</p>
 * @author s.li
 * @create 2017-06-12-17:14
 */
public class PictureTool extends BaseUtil{

    public static void main(String[] args) throws Exception{
    }

    /**
     * 处理批量上传并剪切图片的数据
     * @param imagePath 要剪切的图片物理路径
     * @param rootDir 项目根目录
     * @param staticPath 静态域名
     * @param cutData 剪切数据
     * @return Map<String,Object> 处理后的图片访问信息
     * @throws Exception
     */
    public static Map<String,Object> cutFixedScaleImage(String imagePath,String rootDir,String staticPath,Map<String,Object> cutData) throws Exception{
       //如果图片物理路径、图片存在、剪切数据不为空则处理
        if(StringUtils.isNotEmpty(imagePath) && new File(imagePath).exists() && ObjectUtils.isNotEmpty(cutData)){
            //得到文件后缀
            String fileFormat = FileUtil.getFileFormat(imagePath);
            //把点替换成下划线，得到新的保存路径
            String savePath = imagePath.replaceAll("\\.","_");
            //获取旋转角度
            int rotate = new Double(Double.parseDouble(cutData.get("rotate").toString())).intValue(),
            //获取要剪切图片的高宽
            newImageWidth = new Double(Double.parseDouble(cutData.get("newImageWidth").toString())).intValue(),
            newImageHeight = new Double(Double.parseDouble(cutData.get("newImageHeight").toString())).intValue(),
            //获取剪切的X、Y坐标
            x = new Double(Double.parseDouble(cutData.get("x").toString())).intValue(),
            y = new Double(Double.parseDouble(cutData.get("y").toString())).intValue();
            //加载要剪切的源图片
            BufferedImage bufferedImage = ImageIO.read(new File(imagePath));
            //得到图片的规格
            Map<String,Object> pcMap = (Map<String,Object>)cutData.get("pc"),mobileMap = (Map<String,Object>)cutData.get("mobile");

            Map<String,Object> returnMap =new TreeMap<>();
            boolean status = true;
            if(ObjectUtils.isNotEmpty(pcMap)){
                String pcPath = savePath+"/pc";
                Map<String,String> pcUrlMap = genImage(bufferedImage,staticPath,rootDir,fileFormat,pcPath,pcMap,x,y,newImageWidth,newImageHeight,rotate);
                returnMap.put("pcUrlMap",pcUrlMap);
                status = false;
            }
            if(ObjectUtils.isNotEmpty(mobileMap)){
                String mobilePath = savePath+"/mobile";
                Map<String,String> mobileUrlMap = genImage(bufferedImage,staticPath,rootDir,fileFormat,mobilePath,mobileMap,x,y,newImageWidth,newImageHeight,rotate);
                returnMap.put("mobileUrlMap",mobileUrlMap);
                status = false;
            }
            //如果没有设置剪切规格，则生成一个
            if(status){
                Map<String,Double> large = new HashMap<>();
                large.put("width",Double.parseDouble(cutData.get("newImageWidth").toString()));
                large.put("height",Double.parseDouble(cutData.get("newImageHeight").toString()));
                Map<String,Object> imgSize = new HashMap<>();
                imgSize.put("large",large);
                Map<String,Object> pc = new HashMap<>();
                pc.put("imgSize",imgSize);

                String pcPath = savePath+"/pc";
                Map<String,String> pcUrlMap = genImage(bufferedImage,staticPath,rootDir,fileFormat,pcPath,pc,x,y,newImageWidth,newImageHeight,rotate);
                returnMap.put("pcUrlMap",pcUrlMap);
                status = false;
            }
            File oFile = new File(imagePath);
            if(oFile.exists()){
                oFile.delete();
            }
            return returnMap;
       }
        return null;
    }

    /**
     * 生成新的图片
     * @param bufferedImage 图片内容
     * @param staticPath 静态域名
     * @param rootDir 项目根目录
     * @param fileFormat 图片格式
     * @param savePath 路径路径
     * @param imageMap 图片数据Map
     * @param x 剪切x坐标
     * @param y 剪切y坐标
     * @param newImageWidth 剪切图片的宽
     * @param newImageHeigth 剪切图片的高
     * @param rotate 旋转角度
     * @return  Map<String,String> 路径Map
     * @throws Exception
     */
    private static Map<String,String> genImage(BufferedImage bufferedImage,
                                               String staticPath,
                                               String rootDir,
                                 String fileFormat,String savePath,
                                 Map<String,Object> imageMap,
                                 int x,int y,
                                 int newImageWidth,
                                 int newImageHeigth,int rotate) throws Exception{
        int width=0,height=0;
        Map<String,Object> imgSize = null;
        if(ObjectUtils.isNotEmpty(imageMap)){
            imgSize = (Map<String,Object>)imageMap.get("imgSize");
        }else{
            return null;
        }
        BufferedImage rotateBufferedImage = null;
        if(rotate!=0){//旋转图片
            rotateBufferedImage = RotateImage.rotateImage(bufferedImage,rotate);
        }
        BufferedImage cutBufferedImage = null;

        /*指定截取范围*/
        if(rotateBufferedImage==null){
            cutBufferedImage = bufferedImage.getSubimage(x,y, newImageWidth, newImageHeigth);
        }else{
            cutBufferedImage = rotateBufferedImage.getSubimage(x,y, newImageWidth, newImageHeigth);
        }
        Map<String,String> urlMap = new TreeMap<>();
        //生成大图片
        Map<String,Double> largeMap = (Map<String,Double>)imgSize.get("large");
        if(ObjectUtils.isNotEmpty(largeMap)){//大图片保存
            String largeSavePath = savePath+"/large"+fileFormat;
            urlMap.put("large",largeSavePath.replaceAll(rootDir,staticPath));
            width = largeMap.get("width").intValue();
            height = largeMap.get("height").intValue();
            saveImage(cutBufferedImage,width,height,fileFormat,largeSavePath);
        }
        //生成中图片
        Map<String,Double> mediumMap = (Map<String,Double>)imgSize.get("medium");
        if(ObjectUtils.isNotEmpty(mediumMap)){
            String mediumSavePath = savePath+"/medium"+fileFormat;
            urlMap.put("medium",mediumSavePath.replaceAll(rootDir,staticPath));
            width = mediumMap.get("width").intValue();
            height = mediumMap.get("height").intValue();
            saveImage(cutBufferedImage,width,height,fileFormat,mediumSavePath);
        }
        //生成小图片
            Map<String,Double> smallMap = (Map<String,Double>)imgSize.get("small");
        if(ObjectUtils.isNotEmpty(smallMap)){
            String smallSavePath = savePath+"/small"+fileFormat;
            urlMap.put("small",smallSavePath.replaceAll(rootDir,staticPath));
            width = smallMap.get("width").intValue();
            height = smallMap.get("height").intValue();
            saveImage(cutBufferedImage,width,height,fileFormat,smallSavePath);
        }
        return urlMap;
    }

    private static String saveImage(BufferedImage cutBufferedImage,int width,int height,String fileFormat,String savePath)throws Exception{
        ResampleOp resampleOp = new ResampleOp(width, height);
        BufferedImage saveBuffer = resampleOp.filter(cutBufferedImage,null);
        File saveFile = new File(savePath);
        if(!saveFile.getParentFile().exists()){
            saveFile.getParentFile().mkdirs();
        }
        ImageIO.write(saveBuffer,fileFormat.replaceAll("\\.",""),saveFile);
        return null;
    }

    /**
     * 固定像素缩放
     * @param sourceImg 源图片
     * @param fixedMap 缩放的高宽Map
     * @return 图片处理的路径集合
     * @throws Exception
     */
    public static Map<String,String> fixedScaleImage(File sourceImg,Map<String,Map<String,Integer>> fixedMap,boolean isComplete) throws Exception{
        if(ObjectUtils.isNotEmpty(sourceImg) && ObjectUtils.isNotEmpty(fixedMap)){

            List<String> keyList = new ArrayList<>(fixedMap.keySet());

            String path = sourceImg.getPath();
            int len = path.lastIndexOf(".");
            String _path = path.substring(0,len);

            Map<String,String> urlMap = new HashMap<>();
            BufferedImage bufferedImage = ImageIO.read(sourceImg);
            for(String key : keyList){
                Map<String,Integer> hwMap = fixedMap.get(key);
                int _width = hwMap.get("width");
                int _height = hwMap.get("height");

                String savePath = _path+File.separator+key+File.separator+sourceImg.getName();
                savePath = savePath.replaceAll("\\\\","/");
                resize(bufferedImage,savePath,_height,_width,isComplete);
                urlMap.put(key,savePath);
            }
            return urlMap;
        }
        return null;
    }

    /**
     * 对原图片进行等比例压缩图片
     * @param sourceImg 要压缩的图片
     * @param scaleMap 比例Map，Map中有多少个元素就是压缩多少张
     * @return 返回压缩后文件的URL的Map
     * @throws Exception
     */
    public static Map<String,String> scaleImage(File sourceImg, Map<String,Float> scaleMap) throws Exception{
        if(ObjectUtils.isNotEmpty(sourceImg) && sourceImg.exists() && ObjectUtils.isNotEmpty(scaleMap)){
            String path = sourceImg.getPath();

            int len = path.lastIndexOf(".");
            String _path = path.substring(0,len);
            logger.info("---------_path:"+_path);
            List<String> keyList = new ArrayList<>(scaleMap.keySet());
            Map<String,String> urlMap = new HashMap<>();
            for(String str : keyList){
                String savePath = _path+File.separator+str+File.separator+sourceImg.getName();
                savePath = savePath.replaceAll("\\\\","/");
                logger.info("---------------s:"+savePath);
                float scale = scaleMap.get(str);
                doScaleImage(sourceImg,savePath,scale);
                urlMap.put(str,savePath);
            }
            return urlMap;
        }
        return null;
    }

    /**
     * 压缩图片
     * @param sourceImg 原图片
     * @param savePath 压缩后的文件路径
     * @param scale 压缩百分比
     * @throws Exception
     */
    private static void doScaleImage(File sourceImg,String savePath,float scale) throws Exception{
        BufferedImage imageFirst = ImageIO.read(sourceImg);
        int width = imageFirst.getWidth();// 图片宽度
        int height = imageFirst.getHeight();// 图片高度

        int _width = (int)((scale/100F)*width);//缩放后的宽
        int _height = (int)((scale/100F)*height);//缩放后的高

        //执行压缩图片
        BufferedImage newImage = zoomInImage(imageFirst,_width,_height);
        //获取图片格式
        String format = FileUtil.getFileFormat(savePath);
        saveImage(newImage,format,savePath);
    }

    /**
     * 图片缩放
     * @param bufferedImage 原图片
     * @param height 高度
     * @param width 宽度
     * @param isComplete 比例不对时是否需要补白
     */
    private static void resize(BufferedImage bufferedImage,String savePath, int height, int width, boolean isComplete) throws Exception{

        double w = (double)bufferedImage.getWidth()/(double)width;//得到宽的基数
        double h = (double)bufferedImage.getHeight()/(double)height;//得到高的基数
        //得到基数
        double base = hBase(w>h?w:h,2);
        //通过最大的基数重新计算高宽
        int _width,_height;
        if(w>h){
            _width = width;
            _height = (int)hBase((double)bufferedImage.getHeight()/base,0);
        }else{
            _width = (int)hBase((double)bufferedImage.getWidth()/base,0);
            _height= height;
        }
        BufferedImage newImage = zoomInImage(bufferedImage,_width,_height);
        if (isComplete) {//补白
            BufferedImage b = new BufferedImage(width,height,newImage.getType());
            Graphics2D g = b.createGraphics();
            g.setColor(Color.white);
            g.fillRect(0, 0, width, height);
            if (_width==width){
                g.drawImage(newImage, 0, (height - newImage.getHeight())/2, newImage.getWidth(), newImage.getHeight(), Color.white, null);
            }else{
                g.drawImage(newImage, (width - newImage.getWidth())/2, 0, newImage.getWidth(), newImage.getHeight(), Color.white, null);
            }
            g.dispose();
            newImage = b;
        }
        String formatName = FileUtil.getFileFormat(savePath);
        saveImage(newImage,formatName,savePath);
    }

    /**
     * 对图片进行强制放大或缩小
     * @param originalImage 原始图片
     * @return 返因压缩后的图片
     */
    private static BufferedImage zoomInImage(BufferedImage originalImage, int width, int height) {
        BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());

        Graphics g = newImage.getGraphics();
        g.drawImage(originalImage, 0, 0, width, height, null);
        g.dispose();
        return newImage;
    }

    private static void saveImage(BufferedImage bufferedImage,String formatName,String savePath) throws Exception{
        File f = new File(savePath);
        if(!f.getParentFile().exists()){
            f.getParentFile().mkdirs();
        }
        ImageIO.write(bufferedImage, formatName, new File(savePath));
    }

    private static double hBase(double base,int index){
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(index);
        nf.setRoundingMode(RoundingMode.CEILING);
        String str = nf.format(base);
        return Double.parseDouble(str);
    }
}
